/*
 * Copyright (c) 2016, Freescale Semiconductor, Inc.
 * Copyright 2016-2017 NXP
 * All rights reserved.
 *
 * THIS SOFTWARE IS PROVIDED BY NXP "AS IS" AND ANY EXPRESSED OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL NXP OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */
/* ###################################################################
**     Filename    : main.c
**     Project     : flexcan_encrypted_s32k144
**     Processor   : S32K144_100
**     Version     : Driver 01.00
**     Compiler    : GNU C Compiler
**     Date/Time   : 2016-06-03, 14:05, # CodeGen: 0
**     Abstract    :
**         Main module.
**         This module contains user's application code.
**     Settings    :
**     Contents    :
**         No public methods
**
** ###################################################################*/
/*!
** @file main.c
** @version 01.00
** @brief
**         Main module.
**         This module contains user's application code.
*/
/*!
**  @addtogroup main_module main module documentation
**  @{
*/
/* MODULE main */


/* Including needed modules to compile this module/procedure */
#include "Cpu.h"
#include "clockMan1.h"
#include "canCom1.h"
#include "sbc_uja11691.h"
//#include "sbc_uja1169.h"
#include "lpspiCom1.h"
#include "dmaController1.h"
#include "csec1.h"
#include "lpit1.h"
#include "pin_mux.h"
#if CPU_INIT_CONFIG
  #include "Init_Config.h"
#endif

#include <stdint.h>
#include <stdbool.h>

/******************************************************************************
 * Definitions
 ******************************************************************************/

/* This example is setup to work by default with EVB. To use it with other boards
   please comment the following line
*/
//#define LED_PORT          PORTD
//#define LED_GPIO          PTD
//#define LED_RED           (15U)
//#define LED_GREEN         (16U)
//#define LED_BLUE          (0U)


#define EVB

#ifdef EVB
    #define LED_PORT        PORTD
    #define GPIO_PORT       PTD
    #define PCC_INDEX       PCC_PORTD_INDEX
    #define LED0            15U
    #define LED1            16U
    #define LED2            0U


    #define RXD_GPIO_MASK      0x0010U
    #define RXD_PORT           PORTE
    #define RXD_GPIO           PTE
    #define RXD                (4U)
    #define SW3_GPIO           PTC
    #define SW3_PORT           PORTC
    #define SW3_GPIO_MASK      0x2000U
    #define SW3               (13U)
    #define SW2_GPIO          PTC
    #define SW2_PORT          PORTC
    #define SW2_GPIO_MASK     0x1000U
    #define SW2               (12U)

    #define BTN_GPIO        PTC
    #define BTN1_PIN        13U  //swd3
    #define BTN2_PIN        12U  //swd2
    #define BTN_PORT        PORTC
    #define BTN_PORT_IRQn   PORTC_IRQn

    
    #define LED_PORT          PORTD
    #define LED_GPIO          PTD
    #define PCC_CLOCK         PCC_PORTD_CLOCK
    #define LED_RED           (15U)
    #define LED_GREEN         (16U)
    #define LED_BLUE          (0U)
    #define LPIT_CHANNEL      (0U)
    #define POWER_MODES_NUM   (2u)
    #define RUN               (0u) /* High speed run      */
    #define SLEEP             (1u) /* Very low power stop */
#else
    #define LED_PORT        PORTC
    #define GPIO_PORT       PTC
    #define PCC_INDEX       PCC_PORTC_INDEX
    #define LED0            0U
    #define LED1            1U
    #define LED2            2U

    #define BTN_GPIO        PTC
    #define BTN1_PIN        13U
    #define BTN2_PIN        12U
    #define BTN_PORT        PORTC
    #define BTN_PORT_IRQn   PORTC_IRQn
#endif

/* Use this define to specify if the application runs as master or slave */
#define MASTER
/* #define SLAVE */

/* Definition of the TX and RX message buffers depending on the bus role */
#if defined(MASTER)
    #define TX_MAILBOX  (1UL)
    #define TX_MSG_ID   (1UL)
    #define RX_MAILBOX  (0UL)
    #define RX_MSG_ID   (2UL)
#elif defined(SLAVE)
    #define TX_MAILBOX  (0UL)
    #define TX_MSG_ID   (2UL)
    #define RX_MAILBOX  (1UL)
    #define RX_MSG_ID   (1UL)
#endif


#define LPIT_CHANNEL      (0U)

typedef enum
{
    LED0_CHANGE_REQUESTED = 0x00U,
    LED1_CHANGE_REQUESTED = 0x01U
} can_commands_list;

uint8_t ledRequested = (uint8_t)128;//LED0_CHANGE_REQUESTED;

bool useEncryption = false;

uint8_t timerCount = 0;
/******************************************************************************
 * Function prototypes
 ******************************************************************************/
void SendCANData(uint32_t mailbox, uint32_t messageId, uint8_t * data, uint32_t len);
void buttonISR(void);
void BoardInit(void);
void GPIOInit(void);
void FlexCANInit(void);

/******************************************************************************
 * Functions
 ******************************************************************************/


///* Interrupt service routine for WachDog refreshing. */
static void SBC_FeedWachdogAndLeds(void)
{
    SBC_FeedWatchdog();
    /* Toggle with blue led to show that WachDog is triggered. */
    PINS_DRV_TogglePins(LED_GPIO, 1 << LED_BLUE);

    /* Clear interrupt flag.*/
    LPIT_DRV_ClearInterruptFlagTimerChannels(INST_LPIT1, 1 << LPIT_CHANNEL);
}


/**
 * Button interrupt handler
 */
void buttonISR(void)
{
    /* Check if one of the buttons was pressed */
    uint32_t buttonsPressed = PINS_DRV_GetPortIntFlag(BTN_PORT) &
                                           ((1 << BTN1_PIN) | (1 << BTN2_PIN));
    uint32_t buttons = PINS_DRV_ReadPins(BTN_GPIO);
    bool sendFrame = false;

    if(buttonsPressed != 0)
    {

        /* Set FlexCAN TX value according to the button pressed */
        switch (buttonsPressed)
        {
            case (1 << BTN1_PIN):
                if (buttons & ((1 << BTN2_PIN)))
                {
                    useEncryption = !useEncryption;
                    PINS_DRV_TogglePins(GPIO_PORT, (1 << LED2));
                }
                else
                {
                    ledRequested = LED0_CHANGE_REQUESTED;
                    sendFrame = true;
                }
                /* Clear interrupt flag */
                PINS_DRV_ClearPinIntFlagCmd(BTN_PORT, BTN1_PIN);
                break;
            case (1 << BTN2_PIN):
                ledRequested = LED1_CHANGE_REQUESTED;
                sendFrame = true;
                /* Clear interrupt flag */
                PINS_DRV_ClearPinIntFlagCmd(BTN_PORT, BTN2_PIN);
                break;
            default:
                PINS_DRV_ClearPortIntFlagCmd(BTN_PORT);
                break;
        }

        if (useEncryption && sendFrame)
        {
            uint8_t plaintext[16] = {0,};
            uint8_t ciphertext[16];
            status_t stat;

            plaintext[0] = ledRequested;

            /* Encrypt data using AES-128 ECB and the first non-volatile user key */
            stat = CSEC_DRV_EncryptECB(CSEC_KEY_1, plaintext, 16UL, ciphertext, 1UL);

            if (stat == STATUS_SUCCESS)
            {
                /* Send the information via CAN */
                SendCANData(TX_MAILBOX, TX_MSG_ID, ciphertext, 16UL);
            }
        }
        else if (sendFrame)
        {
            /* Send the information via CAN */
            SendCANData(TX_MAILBOX, TX_MSG_ID, &ledRequested, 1UL);

            PINS_DRV_TogglePins(GPIO_PORT, (1 << LED2));
        }
    }
}

/*
 * @brief: Send data via CAN to the specified mailbox with the specified message id
 * @param mailbox   : Destination mailbox number
 * @param messageId : Message ID
 * @param data      : Pointer to the TX data
 * @param len       : Length of the TX data
 * @return          : None
 */
void SendCANData(uint32_t mailbox, uint32_t messageId, uint8_t * data, uint32_t len)
{
    /* Set information about the data to be sent
     *  - 1 byte in length
     *  - Standard message ID
     *  - Bit rate switch enabled to use a different bitrate for the data segment
     *  - Flexible data rate enabled
     *  - Use zeros for FD padding
     */
    flexcan_data_info_t dataInfo =
    {
            .data_length = len,
            .msg_id_type = FLEXCAN_MSG_ID_STD,
            .enable_brs  = false,
            .fd_enable   = false,
            .fd_padding  = 0U
    };

    /* Configure TX message buffer with index TX_MSG_ID and TX_MAILBOX*/
    FLEXCAN_DRV_ConfigTxMb(INST_CANCOM1, mailbox, &dataInfo, messageId);

 //   flexcan_state_t * state = g_flexcanStatePtr[instance];
 //  g_flexcanStatePtr[INST_CANCOM1]->mbs[mb_idx].state != FLEXCAN_MB_IDLE;

    /* Execute send non-blocking */
    FLEXCAN_DRV_Send(INST_CANCOM1, mailbox, &dataInfo, messageId, data);
}

/*
 * @brief : Initialize clocks, pins and power modes
 */
void BoardInit(void)
{

    /* Initialize and configure clocks
     *  -   Setup system clocks, dividers
     *  -   Configure FlexCAN clock, GPIO
     *  -   see clock manager component for more details
     */
    CLOCK_SYS_Init(g_clockManConfigsArr, CLOCK_MANAGER_CONFIG_CNT,
                        g_clockManCallbacksArr, CLOCK_MANAGER_CALLBACK_CNT);
    CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_FORCIBLE);//CLOCK_MANAGER_POLICY_AGREEMENT CLOCK_MANAGER_POLICY_FORCIBLE

    /* Initialize pins
     *  -   Init FlexCAN and GPIO pins
     *  -   See PinSettings component for more info
     */
    PINS_DRV_Init(NUM_OF_CONFIGURED_PINS, g_pin_mux_InitConfigArr);


    //sbc//
            status_t status = STATUS_SUCCESS;
            sbc_factories_conf_t factoriesConf;

            INT_SYS_SetPriority(LPSPI1_IRQn, 1);

            status = LPSPI_DRV_MasterInit(LPSPICOM1, &lpspiCom1State, &lpspiCom1_MasterConfig0);

            DEV_ASSERT(status == STATUS_SUCCESS);


            /* Initialize LPIT instance 0
                 *  -   Reset and enable peripheral
                 */
                LPIT_DRV_Init(INST_LPIT1, &lpit1_InitConfig);
                /* Initialize LPIT channel 0 and configure it as a periodic counter
                 * which is used to generate an interrupt every second.
                 */

                /* Channel 1 configuration. */
                LPIT_DRV_InitChannel(INST_LPIT1, LPIT_CHANNEL, &lpit1_ChnConfig0);

                /* Install LPIT_ISR as LPIT interrupt handler */
                INT_SYS_InstallHandler(LPIT0_Ch0_IRQn, &SBC_FeedWachdogAndLeds, (isr_t *) 0);
                /* Enable LPIT interrupt. */
                INT_SYS_EnableIRQ(LPIT0_Ch0_IRQn);
                /* Set Priority lower to third place. */
                INT_SYS_SetPriority(LPIT0_Ch0_IRQn, 3U);

                /* Initialize SBC. If status is != STATUS_SUCCESS probably SBC is in FNMC. This mode will be
                 * changed with SBC_ChangeFactoriesSettings.*/
                status = SBC_Init(&sbc_uja11691_InitConfig0, LPSPICOM1);

                /* Start Feeding of WachDog by LPIT timer interrupts. */
                LPIT_DRV_StartTimerChannels(INST_LPIT1, 1U << LPIT_CHANNEL);


     //       status = SBC_Init(&sbc_uja11691_InitConfig0, LPSPICOM1);

            status = SBC_GetFactoriesSettings(&factoriesConf);
               DEV_ASSERT(status == STATUS_SUCCESS);
               if(factoriesConf.control.fnmc == SBC_UJA_SBC_FNMC_EN ||
                       factoriesConf.control.sdmc == SBC_UJA_SBC_SDMC_EN ||
                       factoriesConf.control.slpc == SBC_UJA_SBC_SLPC_IG)
               {
                   /* Set correct settings. */
                   factoriesConf.control.fnmc = SBC_UJA_SBC_FNMC_DIS;
                   factoriesConf.control.sdmc = SBC_UJA_SBC_SDMC_DIS;
                   factoriesConf.control.slpc = SBC_UJA_SBC_SLPC_AC;

                   /* If this function return SBC_NVN_ERROR. Factory settings must be preset
                    * to default state by Hardware configuration. Please read
                    * SBC_ChangeFactoriesSettings descriptions for correct settings.
                    * Conditions for Hardware reset value are
                    * -pin RSTN is held LOW
                    * -CANH is pulled up to VBAT
                    * -CANL is pulled down to GND
                    * When HW reset is done you can change factory settings by running
                    * this example. Be carefully device will be reseted,
                    * initialization sequence must be done again. Run the example again
                    * with new configuration.
                    * */
                   status = SBC_ChangeFactoriesSettings(&factoriesConf);
                   DEV_ASSERT(status == STATUS_SUCCESS);
               }
              SBC_SetMode(SBC_UJA_MODE_MC_NORMAL);
               /* Set interrupt priorities. */
               INT_SYS_SetPriority(SysTick_IRQn, 0);
}

/*
 * @brief Function which configures the LEDs and Buttons
 */
void GPIOInit(void)
{
    /* Output direction for LEDs */
    PINS_DRV_SetPinsDirection(GPIO_PORT, (1 << LED2) | (1 << LED1) | (1 << LED0));

    /* Set Output value LEDs */
    PINS_DRV_ClearPins(GPIO_PORT, 1 << LED1);
    PINS_DRV_SetPins(GPIO_PORT, 1 << LED2);

    /* Setup button pin */
    PINS_DRV_SetPinsDirection(BTN_GPIO, ~((1 << BTN1_PIN)|(1 << BTN2_PIN)));

    /* Setup button pins interrupt */
    // PINS_DRV_SetPinIntSel(BTN_PORT, BTN1_PIN, PORT_INT_RISING_EDGE);
    // PINS_DRV_SetPinIntSel(BTN_PORT, BTN2_PIN, PORT_INT_RISING_EDGE);

    // /* Install buttons ISR */
    // INT_SYS_InstallHandler(BTN_PORT_IRQn, &buttonISR, NULL);

    // /* Enable buttons interrupt */
    // INT_SYS_EnableIRQ(BTN_PORT_IRQn);
}

/*
 * @brief Initialize FlexCAN driver and configure the bit rate
 */
void FlexCANInit(void)
{
    /*
     * Initialize FlexCAN driver
     *  - 8 byte payload size
     *  - FD enabled
     *  - Bus clock as peripheral engine clock
     */
    FLEXCAN_DRV_Init(INST_CANCOM1, &canCom1_State, &canCom1_InitConfig0);
    /* Enable buttons interrupt */
     // INT_SYS_EnableIRQ(CAN0_ORed_0_15_MB_IRQn);
}

//volatile int exit_code = 0;
/* User includes (#include below this line is not maintained by Processor Expert) */

/*!
  \brief The main function for the project.
  \details The startup initialization sequence is the following:
 * - __start (startup asm routine)
 * - __init_hardware()
 * - main()
 *   - PE_low_level_init()
 *     - Common_Init()
 *     - Peripherals_Init()
*/
int main(void)
{

    /* Do the initializations required for this application */
    BoardInit();
    GPIOInit();//

    // OSIF_TimeDelay(200);
    FlexCANInit();

 //   CSEC_DRV_Init(&csec1_State);

    /* Set Output value LED0 & LED_RED */
    PINS_DRV_SetPins(GPIO_PORT, 1 << LED0);
	PINS_DRV_SetPins(GPIO_PORT, 1 << LED1);
	PINS_DRV_SetPins(GPIO_PORT, 1 << LED2);

    /* Set information about the data to be received
     *  - 1 byte in length
     *  - Standard message ID
     *  - Bit rate switch enabled to use a different bitrate for the data segment
     *  - Flexible data rate enabled
     *  - Use zeros for FD padding
     */
    flexcan_data_info_t dataInfo =
    {
            .data_length = 1U,
            .msg_id_type = FLEXCAN_MSG_ID_STD,
            .enable_brs  = false,
            .fd_enable   = false,
            .fd_padding  = 0U
    };

    /* Configure RX message buffer with index RX_MSG_ID and RX_MAILBOX */
    FLEXCAN_DRV_ConfigRxMb(INST_CANCOM1, RX_MAILBOX, &dataInfo, RX_MSG_ID);
    status_t transSta=STATUS_SUCCESS;
    status_t status = STATUS_SUCCESS;

    sbc_trans_stat_t transStatus;
    sbc_mode_mc_t mode = SBC_UJA_MODE_MC_SLEEP;
    sbc_evn_capt_t event;
    sbc_trans_stat_t Sbc_Can_Status;

    while(1)
    {

        transSta=SBC_GetCanStatus(&transStatus);
        SendCANData(TX_MAILBOX, TX_MSG_ID, &ledRequested, 1UL);

        

        /* Check SBC mode each 400ms. */
        if(timerCount >= 2)
        {
            status = SBC_GetMode(&mode);
            if(( mode== SBC_UJA_MODE_MC_NORMAL))
            {
                /* Turn on Green Led. */
                // PINS_DRV_ClearPins(LED_GPIO, 1 << LED_GREEN);
                PINS_DRV_TogglePins(LED_GPIO, 1 << LED_GREEN);
                /* Turn off Red Led. */
                PINS_DRV_SetPins(LED_GPIO, 1 << LED_RED);

                status = SBC_GetCanStatus(&Sbc_Can_Status);
                if(SBC_UJA_TRANS_STAT_CTS_INACT == Sbc_Can_Status.cts )
                    SBC_SetCanConfig(&sbc_uja11691_InitConfig0.can );
                    // SBC_GetCanConfig
            }
            else if ( ( mode== SBC_UJA_MODE_MC_STANDBY) )
            {
                /* Turn off Green Led. */
                PINS_DRV_ClearPins(LED_GPIO, 1 << LED_RED);
                /* Turn on Red Led. */
                PINS_DRV_SetPins(LED_GPIO, 1 << LED_GREEN);
                /* Move MCU to sleep mode. */
               if((PINS_DRV_ReadPins(RXD_GPIO)& RXD_GPIO_MASK) >> RXD)
               {
                   /* Turn off timer if RDX is HIGH in sleep mode. WachDog is off
                   * in autonomous mode when stand by mode is set and RXD is high. */
                //    LPIT_DRV_StopTimerChannels(INST_LPIT1, 1U << LPIT_CHANNEL);
                   /* Wait second in the StandBy mode to demonstrate WachDog
                    * is not needed. */
                   status = SBC_SetMode(SBC_UJA_MODE_MC_NORMAL);
                   OSIF_TimeDelay(1000);
               }
               else
               {
                   /* Turn off Green Led. */
                   PINS_DRV_ClearPins(LED_GPIO, 1 << LED_RED);
                   /* Turn on Red Led. */
                   PINS_DRV_ClearPins(LED_GPIO, 1 << LED_GREEN);
                   status = SBC_SetMode(SBC_UJA_MODE_MC_NORMAL);
                   OSIF_TimeDelay(1000);
               }
               SBC_SetCanConfig(&sbc_uja11691_InitConfig0.can );
            }
            timerCount = 0;
            
    	    
        }
        timerCount++;
    	
        //  PINS_DRV_TogglePins(GPIO_PORT, 1 << LED0);
        /* Go to StandBy mode if SW2 is preset. */
        if((PINS_DRV_ReadPins(SW2_GPIO)& SW2_GPIO_MASK) >> SW2)
        {
            status = SBC_SetMode(SBC_UJA_MODE_MC_STANDBY);
        }

        OSIF_TimeDelay(200);
        

//
//
//        /* Define receive buffer */
//        flexcan_msgbuff_t recvBuff;
//
//        /* Start receiving data in RX_MAILBOX. */
//        FLEXCAN_DRV_Receive(INST_CANCOM1, RX_MAILBOX, &recvBuff);
//
//
//
//        /* Wait until the previous FlexCAN receive is completed */
//        while(FLEXCAN_DRV_GetTransferStatus(INST_CANCOM1, RX_MAILBOX) == STATUS_BUSY);
//        if (useEncryption)
//        {
//            /* Check the length of the received message */
//            if (recvBuff.dataLen == 16)
//            {
//                status_t stat;
//
//                /* Decrypt data using AES-128 ECB and the first non-volatile user key */
//                stat = CSEC_DRV_DecryptECB(CSEC_KEY_1, recvBuff.data, 16UL, recvBuff.data, 1UL);
//
//                if (stat != STATUS_SUCCESS)
//                {
//                    continue;
//                }
//            }
//            else
//            {
//                continue;
//            }
//        }
//
//        /* Check the received message ID and payload */
//        if((recvBuff.data[0] == LED0_CHANGE_REQUESTED) &&
//                recvBuff.msgId == RX_MSG_ID)
//        {
//            /* Toggle output value LED1 */
//            PINS_DRV_TogglePins(GPIO_PORT, (1 << LED0));
//        }
//        else if((recvBuff.data[0] == LED1_CHANGE_REQUESTED) &&
//                recvBuff.msgId == RX_MSG_ID)
//        {
//            /* Toggle output value LED0 */
//            PINS_DRV_TogglePins(GPIO_PORT, (1 << LED1));
//        }
    }
  //  (void) status;


  return 0;

}
